const interactWithFiled = require('./InteractWithFiled')
const MINPacket = require('./MINPacket')
const encoding = require('../encoding')
const {CongestionMark} = require('../component/CongestionMark')
const CanBePrefix = require('../component/CanBePrefix')
const MustBeRefresh = require('../component/MustBeRefresh')
const InterestLifeTime = require('../component/InterestLifeTime')
const {IncomingLogicFaceId} = require("../component/IncomingLogicFaceId");
const {Nonce} = require('../component/Nonce')
const {HopLimit} = require('../component/HopLimit')
const {createContentInterestIdentifierByComponents} = require("../component/IdentifierWrapper");
const {Payload} = require('../component/Payload')
const {TTL} = require('../component/TTL')
const {NackHeader} = require('../component/NackHeader')
const {Identifier} = require('../component/Identifier')


//
// 表示一个通用的内容兴趣包
//
// @Description:
//	1. 包格式如下：
//		Interest = 5 TLV-LENGTH
//             { InterestIdentifier }        => 标识区
//             { Signature }                 => 签名区
//             {                             => 只读区
//                 [CanBePrefix]
//                 [MustBeRefresh]
//                 [InterestLifeTime]
//                 [Nonce]
//                 [HopLimit]
//                 <Payload>
//             }
//             {                             => 可变区
//                 {                         => 受保护区
//                     [CongestionMark]
//                 }
//                 {                         => 非受保护区
//                     [TTL]
//					   [IncomingLogicFaceId]
//                 }
//             }
//
class Interest extends interactWithFiled.InteractWithFiled{
    constructor() {
        super();
        this.MINPacket = new MINPacket()
        this.CanBePrefix = new CanBePrefix.CanBePrefix()
        this.MushBeRefresh = new MustBeRefresh.MustBeRefresh()
        this.InterestLifeTime = new InterestLifeTime.InterestLifeTime()
        this.Nonce = new Nonce()
        this.HopLimit = new HopLimit()
        this.Payload = new Payload()
        this.TTL = new TTL()
        this.NackHeader = new NackHeader()
        this.CongestionMark = new CongestionMark()
        this.Name = new Identifier()
        this.IsCommandInterest = false
        this.InComingLogicFaceId = new IncomingLogicFaceId()
    }

    /**
     * 获取内容兴趣包的名字
     * @returns {Identifier}
     */
    getName(){
        return this.Name
    }

    /**
     * 设置内容兴趣包的名字
     * @param identifier
     */
    setName(identifier){
        this.Name = identifier
    }

    /**
     * 判断一个指定的名字和当前的兴趣包的名字是否匹配
     * TODO 待实现
     * @param identifier
     */
    matchesName(identifier){
        throw new Error("implement me")
    }

    /**
     * 判断一个内容兴趣包和一个内容数据包是否匹配
     * TODO 待实现
     * @param data
     */
    matchesData(data){
        throw new Error("implement me")
    }

    /**
     * 判断一个内容兴趣包和当前兴趣包是否匹配
     * TODO 待实现
     * @param interest
     */
    matchesInterest(interest){
        throw new Error("implement me")
    }

    /**
     * 展示兴趣包的 URI
     * @return string
     */
    toUri(){
        return this.Name.toUri()
    }

    extraDataFromFields() {
        this.doExtraDataFromFields(this.MINPacket)
    }
    /**
     * 从 MINPacket 的分区中提取出 Interest 的各项属性
     * DONE 整合4个field
     */
    doExtraDataFromFields(MINPacket){
        /////////////////////////////////////////////////////////////
        //// 解析可变区
        //             {                             => 可变区
        //                 {                         => 受保护区
        //                     [CongestionMark]
        //                 }
        //                 {                         => 非受保护区
        //                     [TTL]
        //                     [IncomingLogicFaceId]
        //                 }
        //             }
        /////////////////////////////////////////////////////////////
        try {
            let block = MINPacket.MutableField.mutableProtectField.getBlockByType(encoding.tlv.ComponentType.TlvCongestionMark)
            // block为空则抛出异常
            if (block !== undefined) {
                // throw new InterestError()
                this.CongestionMark.wireDecode(block)
            }

            block = MINPacket.MutableField.mutableDangerousField.getBlockByType(encoding.tlv.ComponentType.TlvTTL)
            if (block !== undefined) {
                // throw new InterestError()
                this.TTL.wireDecode(block)
            }
            block = MINPacket.MutableField.mutableDangerousField.getBlockByType(encoding.tlv.ComponentType.TlvIncomingLogicFaceId)
            if (block !== undefined) {
                // throw new InterestError()
                this.InComingLogicFaceId.wireDecode(block)
            }
            /////////////////////////////////////////////////////////////
            //// 解析只读区
            //             {                             => 只读区
            //                 [CanBePrefix]
            //                 [MustBeRefresh]
            //                 [InterestLifeTime]
            //                 [Nonce]
            //                 [HopLimit]
            //                 [NackHeader]
            //                 <Payload>
            //             }
            /////////////////////////////////////////////////////////////

            let elements = MINPacket.ReadOnlyField.getBlocks()
            for (let i = 0; i < elements.length; i++) {
                let element = elements[i]
                switch (element.getType()) {
                    case encoding.tlv.ComponentType.TlvCanBePrefix:
                        this.CanBePrefix.wireDecode(element)
                        break
                    case encoding.tlv.ComponentType.TlvMustBeRefresh:
                        this.MushBeRefresh.wireDecode(element)
                        break
                    case encoding.tlv.ComponentType.TlvInterestLifeTime:
                        this.InterestLifeTime.wireDecode(element)
                        break
                    case encoding.tlv.ComponentType.TlvNonce:
                        this.Nonce.wireDecode(element)
                        break
                    case encoding.tlv.ComponentType.TlvHopLimit:
                        this.HopLimit.wireDecode(element)
                        break
                    case encoding.tlv.ComponentType.TlvPayload:
                        this.Payload.wireDecode(element)
                        break
                    case encoding.tlv.ComponentType.TlvNackHeader:
                        this.NackHeader.wireDecode(element)
                        break
                    default:
                    // TODO: 这边可以规定哪些范围是自定义的，哪些是预留的，然后根据需要这边抛出错误
                }
            }

            /////////////////////////////////////////////////////////////
            //// 解析标识区
            /////////////////////////////////////////////////////////////
            let interestIdentifier = MINPacket.IdentifierField.getIdentifierByType(encoding.tlv.ComponentType.TlvIdentifierContentInterest)
            if (interestIdentifier === undefined) {
                throw new InterestError()
            }
            this.setName(interestIdentifier.getIdentifier())
        } catch (e) {
            throw e
        }
        
    }

    fillDataToFields() {
        this.doFillDataToFields(this.MINPacket)
    }
    /**
     * 将 Interest 的各项属性填充到 MINPacket 中定义的对应分区当中
     * DONE 整合4个field
     */
    doFillDataToFields(MINPacket){
        /////////////////////////////////////////////////////////////
        //// 填充可变区
        /////////////////////////////////////////////////////////////
        try {
            // 填充可变受保护区
            // 1. 清除可变受保护区
            MINPacket.MutableField.mutableProtectField.clearBlocks()
            // CongestionMark
            let cblock = this.CongestionMark.selfWireEncode(this.CongestionMark)
            MINPacket.MutableField.mutableProtectField.addBlock(cblock)

            // 填充可变非受保护区（TTL）
            MINPacket.MutableField.mutableDangerousField.clearBlocks()
            // CongestionMark
            let tblock = this.TTL.selfWireEncode(this.TTL)
            MINPacket.MutableField.mutableDangerousField.addBlock(tblock)
            // IncomingLogicFaceId
            if (this.InComingLogicFaceId.isInitial())
            {
                let iBlock = this.InComingLogicFaceId.selfWireEncode(this.InComingLogicFaceId)
                MINPacket.MutableField.mutableDangerousField.addBlock(iBlock)
            }
            /////////////////////////////////////////////////////////////
            //// 填充只读区
            /////////////////////////////////////////////////////////////

            MINPacket.ReadOnlyField.clearBlocks()
            // CanBePrefix
            if (this.CanBePrefix.getCanBePrefix()) {
                let block = this.CanBePrefix.selfWireEncode(this.CanBePrefix)
                MINPacket.ReadOnlyField.addBlock(block)
            }
            // MustBeRefresh
            if (this.MushBeRefresh.getMustBeRefresh()) {
                let block = this.MushBeRefresh.selfWireEncode(this.MushBeRefresh)
                MINPacket.ReadOnlyField.addBlock(block)
            }
            // InterestLifeTime
            if (!this.InterestLifeTime.isInitial()) {
                // 默认生存期为4s
                this.InterestLifeTime.setInterestLifeTime(4000)
            }
            let block = this.InterestLifeTime.selfWireEncode(this.InterestLifeTime)
            MINPacket.ReadOnlyField.addBlock(block)
            // Nonce
            if (!this.Nonce.isInitial()) {
                // 如果没有指定随机数，随机生成一个随机数
                this.Nonce.refreshNonce()
            }
            let nblock = this.Nonce.selfWireEncode(this.Nonce)
            MINPacket.ReadOnlyField.addBlock(nblock)
            // HopLimit
            if (this.HopLimit.isInitial()) {
                let block = this.HopLimit.selfWireEncode(this.HopLimit)
                MINPacket.ReadOnlyField.addBlock(block)
            }

            // NackHeader
            if (this.NackHeader.isInitial()) {
                let nblock = this.NackHeader.selfWireEncode(this.NackHeader)
                MINPacket.ReadOnlyField.addBlock(nblock)
            }

            // Payload
            let pblock = this.Payload.selfWireEncode(this.Payload)
            MINPacket.ReadOnlyField.addBlock(pblock)


            /////////////////////////////////////////////////////////////
            //// 填充标识区
            /////////////////////////////////////////////////////////////
            MINPacket.IdentifierField.clearIdentifiers()
            let newIdentifierWrapper = createContentInterestIdentifierByComponents(this.Name.getComponents())
            MINPacket.IdentifierField.addIdentifier(newIdentifierWrapper)
        } catch (e) {
            throw e
        }
        
    }

    /**
     * 将 Interest 线速编码为一个 TLV
     * @param enc {encoding.Encoder}
     * @returns {number} 编码长度
     */
    wireEncode(enc){
        // 首先将各项属性填充到分区当中
        try {
            this.fillDataToFields()
            if (this.IsCommandInterest)
                this.MINPacket.packetType = encoding.tlv.PacketType.TlvPacketMINManagement
            else
                this.MINPacket.packetType = encoding.tlv.PacketType.TlvPacketMINCommon
            return this.MINPacket.wireEncode(enc)
        } catch (e) {
            throw e
        }
        
    }

    /**
     * 从 TLV Block 中解码出一个 Interest
     * @param block {encoding.Block}
     *
     * @description 解码过程：block -> minpacket -> interest
     */
    wireDecode(block) {
        try {
            this.MINPacket.wireDecode(block)
            if (this.MINPacket.packetType === encoding.tlv.PacketType.TlvPacketMINManagement)
                this.IsCommandInterest = true
            this.extraDataFromFields()
        } catch (e) {
            throw e
        }
        
    }
}

function createInterestByMINPacket(packet) {
    let interest = new Interest();
    if (packet.packetType === encoding.tlv.PacketType.TlvPacketMINManagement)
        interest.IsCommandInterest = true
    try {
        interest.doExtraDataFromFields(packet)
        return interest
    } catch (e) {
        throw e
    }
}
class InterestError extends Error {
    constructor(m) {
        super(m)
        this.name = 'MINPacketError'
    }

    error() {
        console.log(`${this.name}: ${this.message}`)
    }
}
module.exports = {
    Interest: Interest,
    createInterestByMINPacket: createInterestByMINPacket
}